﻿using UnityEngine;
using System.Collections;
using UnityEngine.Events;

namespace RootMotion.FinalIK {

	public partial class IKSolverVR: IKSolver {

		[System.Serializable]
		public class Footstep {

			public float stepSpeed = 3f;
			public Vector3 characterSpaceOffset;

			public Vector3 position;
			public Quaternion rotation = Quaternion.identity;
			public Quaternion stepToRootRot = Quaternion.identity;
			public bool isStepping { get { return stepProgress < 1f; }}
			public bool isSupportLeg;
            public bool relaxFlag;

			public float stepProgress { get; private set; }
			public Vector3 stepFrom;
			public Vector3 stepTo;
			public Quaternion stepFromRot = Quaternion.identity;
			public Quaternion stepToRot = Quaternion.identity;
			private Quaternion footRelativeToRoot = Quaternion.identity;
			private float supportLegW;
			private float supportLegWV;

			public Footstep (Quaternion rootRotation, Vector3 footPosition, Quaternion footRotation, Vector3 characterSpaceOffset) {
				this.characterSpaceOffset = characterSpaceOffset;
				Reset(rootRotation, footPosition, footRotation);
                footRelativeToRoot = Quaternion.Inverse(rootRotation) * rotation;
            }

			public void Reset(Quaternion rootRotation, Vector3 footPosition, Quaternion footRotation) {
				position = footPosition;
				rotation = footRotation;
				stepFrom = position;
				stepTo = position;
				stepFromRot = rotation;
				stepToRot = rotation;
				stepToRootRot = rootRotation;
				stepProgress = 1f;
			}

			public void StepTo(Vector3 p, Quaternion rootRotation, float stepThreshold) {
                if (relaxFlag)
                {
                    stepThreshold = 0f;
                    relaxFlag = false;
                }

                if (Vector3.Magnitude(p - stepTo) < stepThreshold && Quaternion.Angle(rootRotation, stepToRootRot) < 25f) return;
                stepFrom = position;
				stepTo = p;
				stepFromRot = rotation;
				stepToRootRot = rootRotation;
				stepToRot = rootRotation * footRelativeToRoot;
				stepProgress = 0f;
			}

			public void UpdateStepping(Vector3 p, Quaternion rootRotation, float speed, float deltaTime) {
				stepTo = Vector3.Lerp (stepTo, p, deltaTime * speed);
				stepToRot = Quaternion.Lerp (stepToRot, rootRotation * footRelativeToRoot, deltaTime * speed);

				stepToRootRot = stepToRot * Quaternion.Inverse(footRelativeToRoot);
			}

			public void UpdateStanding(Quaternion rootRotation, float minAngle, float speed, float deltaTime) {
				if (speed <= 0f || minAngle >= 180f) return;

				Quaternion r = rootRotation * footRelativeToRoot;
				float angle = Quaternion.Angle (rotation, r);
				if (angle > minAngle) rotation = Quaternion.RotateTowards (rotation, r, Mathf.Min (deltaTime * speed * (1f - supportLegW), angle -minAngle));
			}

			public void Update(InterpolationMode interpolation, UnityEvent onStep, float deltaTime) {
				float supportLegWTarget = isSupportLeg ? 1f : 0f;
				supportLegW = Mathf.SmoothDamp (supportLegW, supportLegWTarget, ref supportLegWV, 0.2f);

				if (!isStepping) return;

				stepProgress = Mathf.MoveTowards(stepProgress, 1f, deltaTime * stepSpeed);

				if (stepProgress >= 1f) onStep.Invoke ();

				float stepProgressSmooth = RootMotion.Interp.Float(stepProgress, interpolation);

				position = Vector3.Lerp(stepFrom, stepTo, stepProgressSmooth);
				rotation = Quaternion.Lerp(stepFromRot, stepToRot, stepProgressSmooth);
			}
		}
	}
}
